package edu.luc.cs.laufer.cs473.shapealgebra

object ExtendedShapeSize extends ExtendedShapeAlgebra[Int] {
  // forward methods for original shapes at object level
  override def visitCircle(c: Circle) = ShapeSize.visitCircle(c)
  // TODO: methods for the other original shapes
  override def visitRectangle(r: Rectangle) = ShapeSize.visitRectangle(r)
  override def visitLocation(r: Int, l: Location) = ShapeSize.visitLocation(r,l)
  override def visitGroup(rs: Seq[Int], g: Group) = ShapeSize.visitGroup(rs,g)
  // new methods for extended shapes
  override def visitStroke(r: Int, s: Stroke) = r
  override def visitFill(r: Int, f: Fill) = r
  override def visitOutline(r: Int, o: Outline) = r
  override def visitPoint(p: Point) = 1
  override def visitPolygon(poly: Polygon) = 1
  // TODO: methods for the other additional (extended) shapes
}

object ExtendedShapeDepth extends ExtendedShapeAlgebra[Int] {
  // TODO: all methods defined from scratch
  override def visitCircle(c: Circle) = 1
  override def visitRectangle(r: Rectangle) = 1
  override def visitLocation(r: Int, l: Location) = r + 1
  override def visitGroup(rs: Seq[Int], g: Group) = rs.reduceLeft((l,r)=>(if(l>r) l else r)) + 1
  override def visitStroke(r: Int, s: Stroke) = r + 1
  override def visitFill(r: Int, f: Fill) = r+1
  override def visitOutline(r: Int, o: Outline) = r +1
  override def visitPoint(p:Point) = 1
  override def visitPolygon(poly: Polygon) = 1
}

class ExtendedBoundingBox extends BoundingBox with ExtendedShapeAlgebra[Location] {
  // methods for original shapes inherited at class level
  // TODO: methods for the other additional (extended) shapes
  override def visitStroke(r: Location, s: Stroke) = r
  // etc.
  override def visitFill(r: Location, f: Fill) = r
  override def visitOutline(r: Location, o: Outline) = r
  override def visitPoint(p:Point) = Location(p.x, p.y, p)
  override def visitPolygon(poly: Polygon) ={
    val xl = poly.points.map(_.x).reduceLeft(Math.min)
    val xr = poly.points.map(_.x).reduceLeft(Math.max)
    val yd = poly.points.map(_.y).reduceLeft(Math.min)
    val yu = poly.points.map(_.y).reduceLeft(Math.max)
    Location(xl, yd, Rectangle(xr - xl, yu - yd))
  }
}

object ExtendedBoundingBox extends ExtendedBoundingBox